package com.cl.code.common.model.number;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * SerialNumberGenerator 是一个灵活的序列号生成工具类。
 * 支持前缀、自定义连接符、指定长度和字符集（大写、小写、数字、符号）组合的序列号生成。
 */
public class SerialNumberGenerator implements NumberGenerator {

    // 序列号前缀
    private final String prefix;

    // 前缀与序列号之间的连接符
    private final Character connector;

    // 随机字符部分的长度
    private final int length;

    // 是否使用大写字母
    private final boolean useUpper;

    // 是否使用小写字母
    private final boolean useLower;

    // 是否使用数字
    private final boolean useDigits;

    // 是否使用特殊符号
    private final boolean useSymbols;

    // 实际使用的字符池，根据配置构建
    private final char[] charPool;

    /**
     * 构造函数由 Builder 调用
     */
    private SerialNumberGenerator(Builder builder) {
        this.prefix = builder.prefix;
        this.connector = builder.connector;
        this.length = builder.length;
        this.useUpper = builder.useUpper;
        this.useLower = builder.useLower;
        this.useDigits = builder.useDigits;
        this.useSymbols = builder.useSymbols;
        this.charPool = buildCharPool(); // 构建字符池
    }

    /**
     * 创建一个新的 Builder 实例
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * 使用构造器中指定的 prefix 和 connector 生成序列号
     */
    @Override
    public String generate() {
        return generateInternal(this.prefix, this.connector, this.length);
    }

    /**
     * 使用指定的 length，使用构造器中指定的 prefix 和 connector 生成序列号
     */
    @Override
    public String generate(int length) {
        return generateInternal(this.prefix, this.connector, length);
    }

    /**
     * 使用指定的 prefix，使用构造器中指定的 connector 和 length 生成序列号
     */
    @Override
    public String generate(String prefix) {
        return generateInternal(prefix, this.connector, this.length);
    }

    /**
     * 使用指定的 prefix 和 length，使用构造器中指定的 connector 生成序列号
     */
    @Override
    public String generate(String prefix, int length) {
        return generateInternal(prefix, this.connector, length);
    }

    /**
     * 使用指定的 prefix 和 length 和 connector 生成序列号
     */
    @Override
    public String generate(String prefix, Character connector, int length) {
        return generateInternal(prefix, connector, length);
    }

    /**
     * 实际生成序列号的逻辑函数
     */
    private String generateInternal(String pfx, Character conn, int length) {
        // 提前估算容量，减少 StringBuilder 扩容
        int estimateLength = (pfx == null ? 0 : pfx.length()) +
                (conn == null ? 0 : 1) +
                length;

        StringBuilder sb = new StringBuilder(estimateLength);

        // 添加前缀和连接符
        if (pfx != null && !pfx.isEmpty()) {
            sb.append(pfx);
            if (conn != null) {
                sb.append(conn);
            }
        }

        char[] pool;
        // charPool拷贝并排除掉连接符
        if (conn != null) {
            // 第一次遍历统计保留字符数量
            int count = 0;
            for (char c : this.charPool) {
                if (c != conn) count++;
            }
            if (count == this.charPool.length) {
                pool = this.charPool;
            } else {
                // 创建结果数组（一定是新数组，不管有没有排除）
                pool = new char[count];
                int index = 0;

                // 第二次遍历复制保留字符
                for (char c : this.charPool) {
                    if (c != conn) {
                        pool[index++] = c;
                    }
                }
            }
        } else {
            pool = this.charPool;
        }

        // 随机生成字符部分
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int i = 0; i < length; i++) {
            sb.append(pool[random.nextInt(pool.length)]);
        }

        return sb.toString();
    }

    /**
     * 构建用于生成序列号的字符池，根据配置选择字符类型
     */
    private char[] buildCharPool() {
        List<Character> pool = new ArrayList<>();

        // 添加大写字母 A-Z
        if (useUpper) {
            for (char c = 'A'; c <= 'Z'; c++) pool.add(c);
        }

        // 添加小写字母 a-z
        if (useLower) {
            for (char c = 'a'; c <= 'z'; c++) pool.add(c);
        }

        // 添加数字 0-9
        if (useDigits) {
            for (char c = '0'; c <= '9'; c++) pool.add(c);
        }

        // 添加常用符号
        if (useSymbols) {
            for (char c : "!@#$%^&*()-_=+[]{}".toCharArray()) pool.add(c);
        }

        // 将 List 转为 char[] 数组，提高随机访问性能
        char[] result = new char[pool.size()];
        for (int i = 0; i < pool.size(); i++) {
            result[i] = pool.get(i);
        }
        return result;
    }

    /**
     * Builder 模式，用于灵活构造 SerialNumberGenerator 对象
     */
    public static class Builder {
        private String prefix = "";
        private Character connector = '-'; // 默认连接符为 '-'
        private int length = 10;
        private boolean useUpper = false;
        private boolean useLower = false;
        private boolean useDigits = false;
        private boolean useSymbols = false;

        /**
         * 设置前缀
         */
        public Builder prefix(String prefix) {
            this.prefix = prefix;
            return this;
        }

        /**
         * 设置连接符（用于连接前缀和随机部分）
         */
        public Builder connector(Character connector) {
            this.connector = connector;
            return this;
        }

        /**
         * 设置随机部分的长度，最小为 1
         */
        public Builder length(int length) {
            if (length < 1) throw new IllegalArgumentException("Length must be at least 1.");
            this.length = length;
            return this;
        }

        /**
         * 设置是否使用大写字母
         */
        public Builder useUpper(boolean useUpper) {
            this.useUpper = useUpper;
            return this;
        }

        /**
         * 设置是否使用小写字母
         */
        public Builder useLower(boolean useLower) {
            this.useLower = useLower;
            return this;
        }

        /**
         * 设置是否使用数字
         */
        public Builder useDigits(boolean useDigits) {
            this.useDigits = useDigits;
            return this;
        }

        /**
         * 设置是否使用特殊符号
         */
        public Builder useSymbols(boolean useSymbols) {
            this.useSymbols = useSymbols;
            return this;
        }

        /**
         * 构造最终的 SerialNumberGenerator 实例
         * 如果没有启用任何字符集，将抛出异常
         */
        public SerialNumberGenerator build() {
            if (!useUpper && !useLower && !useDigits && !useSymbols) {
                throw new IllegalArgumentException("At least one character type (upper, lower, digits, symbols) must be enabled.");
            }
            return new SerialNumberGenerator(this);
        }
    }
}
